﻿using System;
using System.ServiceModel;
using System.ServiceModel.Discovery;
using Devtm.ServiceModel.Discovery.Result;


namespace Devtm.ServiceModel.Discovery
{



    /// <summary>
    /// Cette classe s'occupe de recevoir les demandes et de les redispatcher
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults=true)]
    public class DiscoveryProxyService : System.ServiceModel.Discovery.DiscoveryProxy
    {


        #region private fields

        ServiceDirectoryStore onlineServices;
       
        #endregion


        #region Ctor



        public static ServiceHost GetDiscoveryService(Uri probeEndpointAddress, Uri announcementEndpointAddress, System.ServiceModel.Channels.Binding binding)
        {

            ServiceHost proxyServiceHost = new ServiceHost(new DiscoveryProxyService());

            // Add DiscoveryEndpoint to receive Probe and Resolve messages
            DiscoveryEndpoint discoveryEndpoint
                = new DiscoveryEndpoint(binding, new EndpointAddress(probeEndpointAddress)) { IsSystemEndpoint = false };

            proxyServiceHost.AddServiceEndpoint(discoveryEndpoint);

            // Add AnnouncementEndpoint to receive Hello and Bye announcement messages
            AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(binding, new EndpointAddress(announcementEndpointAddress));
            proxyServiceHost.AddServiceEndpoint(announcementEndpoint);

            return proxyServiceHost;

        }



        public DiscoveryProxyService()
        {
            this.onlineServices = new ServiceDirectoryStore();
        }

        //protected override IAsyncResult BeginShouldRedirectFind(FindCriteria resolveCriteria, AsyncCallback callback, object state)
        //{            
        //    return base.BeginShouldRedirectFind(resolveCriteria, callback, state);
        //}

        //protected override IAsyncResult BeginShouldRedirectResolve(ResolveCriteria findCriteria, AsyncCallback callback, object state)
        //{
        //    return base.BeginShouldRedirectResolve(findCriteria, callback, state);
        //}

        //protected override bool EndShouldRedirectFind(IAsyncResult result, out System.Collections.ObjectModel.Collection<EndpointDiscoveryMetadata> redirectionEndpoints)
        //{
        //    return base.EndShouldRedirectFind(result, out redirectionEndpoints);
        //}

        //protected override bool EndShouldRedirectResolve(IAsyncResult result, out System.Collections.ObjectModel.Collection<EndpointDiscoveryMetadata> redirectionEndpoints)
        //{
        //    return base.EndShouldRedirectResolve(result, out redirectionEndpoints);
        //}

       #endregion

      
        #region DiscoveryProxy Implementation
        
        #region Add


        /// <summary>
        /// Cette méthode est appelée lorsque le proxy de découverte reçoit un message d'annonce en ligne.
        /// </summary>
        /// <param name="messageSequence"></param>
        /// <param name="endpointDiscoveryMetadata"></param>
        /// <param name="callback"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        protected override IAsyncResult OnBeginOnlineAnnouncement(DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata endpointDiscoveryMetadata, AsyncCallback callback, object state)
        {
            this.onlineServices.AddOnline(endpointDiscoveryMetadata);           
            return new OnOnlineAnnouncementAsyncResult(callback, state);
        }


        /// <summary>
        /// Cette méthode est appelée lorsque le proxy de découverte finit un traitement de message d'annonce.
        /// </summary>
        /// <param name="result"></param>
        protected override void OnEndOnlineAnnouncement(IAsyncResult result)
        {
            OnOnlineAnnouncementAsyncResult.End(result);
        }


        #endregion

        #region Remove

        /// <summary>
        ///  Cette méthode est appelée lorsque le proxy de découverte reçoit un message d'annonce hors connexion.
        /// </summary>
        /// <param name="messageSequence"></param>
        /// <param name="endpointDiscoveryMetadata"></param>
        /// <param name="callback"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        protected override IAsyncResult OnBeginOfflineAnnouncement(DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata endpointDiscoveryMetadata, AsyncCallback callback, object state)
        {
            this.onlineServices.RemoveOnline(endpointDiscoveryMetadata);            
            return new OnOfflineAnnouncementAsyncResult(callback, state);
        }


        /// <summary>
        /// Cette méthode est appelée lorsque le proxy de découverte finit un traitement de message d'annonce hors connexion.
        /// </summary>
        /// <param name="result"></param>
        protected override void OnEndOfflineAnnouncement(IAsyncResult result)
        {
            OnOfflineAnnouncementAsyncResult.End(result);
        }

        #endregion

        #region Find

        /// <summary>
        /// Cette méthode est appelée lorsque le proxy de découverte reçoit une demande de recherche.
        /// </summary>
        /// <param name="findRequestContext"></param>
        /// <param name="callback"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        protected override IAsyncResult OnBeginFind(FindRequestContext findRequestContext, AsyncCallback callback, object state)
        {
            this.onlineServices.MatchFromOnlineService(findRequestContext);
            return new OnFindAsyncResult(callback, state);
        }


        //protected override IAsyncResult OnBeginFind(FindRequest findRequest, AsyncCallback callback, object state)
        //{
        //    Collection<EndpointDiscoveryMetadata> matchingEndpoints = MatchFromCache(findRequest.Criteria);
        //    return new OnFindAsyncResult(
        //                matchingEndpoints,
        //                callback,
        //                state);
        //}

      

        /// <summary>
        /// Cette méthode est appelée lorsque le proxy de découverte finit un traitement de demande de recherche.
        /// </summary>
        /// <param name="result"></param>
        protected override void OnEndFind(IAsyncResult result)
        {
            OnFindAsyncResult.End(result);
        }
  
        #endregion

        #region Resolve

        /// <summary>
        /// Cette méthode est appelée lorsque le proxy de découverte reçoit un message de résolution.
        /// </summary>
        /// <param name="resolveCriteria"></param>
        /// <param name="callback"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        protected override IAsyncResult OnBeginResolve(ResolveCriteria resolveCriteria, AsyncCallback callback, object state)
        {
            return new OnResolveAsyncResult(this.onlineServices.MatchFromOnlineService(resolveCriteria), callback, state);
        }


        //protected override IAsyncResult OnBeginResolve(ResolveRequest resolveRequest, AsyncCallback callback, object state)
        //{
        //    return new OnResolveAsyncResult(
        //        this.proxy.MatchFromOnlineService(resolveRequest.Criteria),
        //        callback,
        //        state);
        //}


        /// <summary>
        /// Cette méthode est appelée lorsque le proxy de découverte finit un traitement de message de résolution.
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        protected override EndpointDiscoveryMetadata OnEndResolve(IAsyncResult result)
        {
            return OnResolveAsyncResult.End(result);
        }


        #endregion

        #endregion

    }

}
